package vn.gameloft.blockbreaker;

import vn.gameloft.blockbreaker.model.Block;
import vn.gameloft.blockbreaker.model.ShapeFactory;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Vector2;

public class MainScreen extends ScreenAdapter {

    private static final int SCREEN_WIDTH = Gdx.graphics.getWidth();
    private static final int SCREEN_HEIGHT = Gdx.graphics.getHeight();
    private static final int GBLOCK_ROWS = 3;
    private static final int GBLOCK_COLS = 7;
    private static final int BLOCK_COUNT = GBLOCK_COLS * GBLOCK_ROWS;
    private static final int GBLOCK_HGAP = SCREEN_WIDTH / 8;
    private static final int GBLOCK_VGAP = SCREEN_HEIGHT / 8;
    private static final float GBLOCK_TOP = SCREEN_HEIGHT - GBLOCK_VGAP * 1.5f;
    private static final float GBLOCK_LEFT = (0.05f * SCREEN_WIDTH);
    private static final int BLOCK_WIDTH = SCREEN_WIDTH / 10;
    private static final int BLOCK_HEIGHT = SCREEN_HEIGHT / 10;

    private static final int BALL_MAX_SPEED = SCREEN_WIDTH / 4;
    private Block blocks;
    private Circle ball;
    private Block bar;
    private BlockBreaker inGame;
    private Vector2 ballSpeed = Vector2.Zero;
    private boolean began = false;

    public MainScreen(BlockBreaker sgm) {
        this.inGame = sgm;
        Gdx.graphics.getGL20().glClearColor(0, 0, 0, 1);
        Gdx.graphics.setDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, false);
        this.ball = new Circle(Gdx.graphics.getWidth() / 2,
                Gdx.graphics.getHeight() / 2, 10);
        this.bar = new Block();
        this.bar.x = SCREEN_WIDTH / 2 - BLOCK_WIDTH / 2;
        this.bar.y = 10;
        this.bar.width = BLOCK_WIDTH;
        this.bar.height = BLOCK_HEIGHT / 2;
        initBlocks();
    }

    @Override
    public void resize(int width, int height) {
        super.resize(SCREEN_WIDTH, SCREEN_HEIGHT);
    }

    @Override
    public void render(float delta) {
        Gdx.graphics.getGL20().glClear(
                GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
        inGame.batch.begin();

        if (!began) {
            if (Gdx.input.justTouched()
                    || Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
                ballSpeed.add((float) Math.random() * BALL_MAX_SPEED / 2
                        + BALL_MAX_SPEED / 2, (float) Math.random()
                        * BALL_MAX_SPEED / 2 + BALL_MAX_SPEED / 2);
                began = true;
            }
        } else {
            // ball move to ground
            if (ball.y - ball.radius < 0 || this.blocks == null) {
                this.inGame.setScreen(new EndScreen(this.inGame));
                this.dispose();
            }
            // ball move to top edge
            else if (ball.y + ball.radius > SCREEN_HEIGHT && ballSpeed.y > 0) {
                ballSpeed.y = -ballSpeed.y;
            }
            // ball move to left, right edge
            if (ball.x - ball.radius < 0 && ballSpeed.x < 0
                    || ball.x + ball.radius > SCREEN_WIDTH && ballSpeed.x > 0) {
                ballSpeed.x = -ballSpeed.x;
            }

            Vector2 c = bar.getCenter(new Vector2());

            // bar move to left side
            if (Gdx.input.isKeyPressed(Input.Keys.LEFT) && c.x > 0) {
                this.bar.x -= SCREEN_WIDTH * delta / 2;
            }
            // bar move to right side
            else if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)
                    && c.x < SCREEN_WIDTH) {
                this.bar.x += SCREEN_WIDTH * delta / 2;
            } else if (Gdx.input.isTouched()) {
                if (Gdx.input.getX() < SCREEN_WIDTH / 2 && c.x > 0) {
                    this.bar.x -= SCREEN_WIDTH * delta / 2;
                } else if(c.x < SCREEN_WIDTH){
                    this.bar.x += SCREEN_WIDTH * delta / 2;
                }
            }

            this.ball.setPosition(this.ball.x + ballSpeed.x * delta,
                    this.ball.y + ballSpeed.y * delta);

            if (bar.isOverlap(this.ball) && ballSpeed.y < 0) {
                float orgSpeed = ballSpeed.len();
                Vector2 v = new Vector2(ball.x - c.x, ball.y - c.y);
                ballSpeed = v.scl(orgSpeed / v.len());
            }
        }

        bar.draw();
        drawBlocksGrid();
        drawBall();
        inGame.batch.end();
    }

    private void drawBall() {

        ShapeRenderer brush = ShapeFactory.getInstance();
        brush.setColor(Color.BLUE);
        brush.begin(ShapeType.Filled);
        brush.circle(ball.x, ball.y, ball.radius);
        brush.end();
    }

    private void initBlocks() {
        this.blocks = new Block();
        this.blocks.set(GBLOCK_LEFT, GBLOCK_TOP, BLOCK_WIDTH, BLOCK_HEIGHT);
        Block lastBlock = this.blocks;
        for (int i = 1; i < BLOCK_COUNT; i++) {
            int blockCol = i % GBLOCK_COLS;
            int blockRow = (i - blockCol) / GBLOCK_COLS;

            Block b = new Block();
            b.set(GBLOCK_LEFT + blockCol * GBLOCK_HGAP, GBLOCK_TOP - blockRow
                    * GBLOCK_VGAP, BLOCK_WIDTH, BLOCK_HEIGHT);
            lastBlock.setNext(b);
            lastBlock = b;
        }
    }

    private void drawBlocksGrid() {
        Block b = this.blocks;
        Vector2 c = new Vector2();
        while (b != null) {
            Block next = b.getNext();
            if (b.isOverlap(this.ball)) {
                b.dispose();
                if (b.equals(this.blocks)) {
                    this.blocks = next;
                }
                // get block center
                b.getCenter(c);
                Vector2 dst = new Vector2(ball.x - c.x, ball.y - c.y);
                float h = Math.abs(dst.x) / b.width;
                float v = Math.abs(dst.y) / b.height;
                if (h > v) {
                    ballSpeed.x = -ballSpeed.x;
                } else {
                    ballSpeed.y = -ballSpeed.y;
                }
            } else {
                b.draw();
            }
            b = next;
        }
    }
}
